home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Tool Chest / Testing & Debugging / General tools / Exceptions.h
Encoding:
C/C++ Source or Header  |  1993-09-17  |  21.9 KB  |  842 lines  |  [TEXT/MPS ]

  1.  
  2. /**************************************************************************************
  3.  
  4. FILENAME
  5.     Exceptions.h
  6.     
  7. DESCRIPTION
  8.     A collection of routines to handle assertions and exceptions.
  9.  
  10. COPYRIGHT
  11.     Copyright © Apple Computer, Inc. 1989-1993
  12.     All rights reserved.
  13.  
  14. ROUTINES
  15.     EXTERNALS
  16.         dprintf
  17.  
  18. MACROS
  19.     EXTERNALS
  20.         SetExceptionOption - resumeLabelsOn / resumeLabelsOff
  21.         check
  22.         ncheck
  23.         check_action
  24.         ncheck_action
  25.         require
  26.         nrequire
  27.         require_action
  28.         nrequire_action
  29.         retry
  30.         resume
  31.  
  32.         
  33. NOTE
  34.     To keep code size down, use these routines and macros with the C compiler option
  35.     -b2 or -b3. This will eliminate duplicate strings.
  36. NOTE
  37.     For more information on exception handling please refer to the book "Object-
  38.     oriented Software Construction" by Bertrand Meyer, Prentice Hall International.
  39.     Also, read the _develop_ article on Exception Handling by Sean Parent.
  40.  
  41. **************************************************************************************/
  42.  
  43. #ifndef __EXCEPTIONS__
  44. #define __EXCEPTIONS__
  45.  
  46. /**************************************************************************************
  47.  
  48. INCLUDES
  49.  
  50. **************************************************************************************/
  51.  
  52. #ifndef        __TYPES__
  53. #include    <Types.h>
  54. #endif
  55.  
  56. /*<FF>*/
  57. /**************************************************************************************
  58.  
  59. CONSTANTS AND CONTROL
  60.  
  61. **************************************************************************************/
  62.  
  63. #define DEBUGOFF        0
  64. #define DEBUGWARN        1
  65. #define DEBUGON            2
  66. #define DEBUGFULL        3
  67.  
  68. #ifndef DEBUGLEVEL
  69.     #define DEBUGLEVEL DEBUGWARN
  70. #endif DEBUGLEVEL
  71.  
  72. /*
  73.     Declare a prototype that is used to ensure proper use of semicolons.
  74. */
  75.  
  76. void PlaceHolder(void);
  77.  
  78. /*
  79.     These macros are used to control the insertion of the resume labels. If off
  80.     then you can have multible requires sharing the same label but cannot resume.
  81. */
  82.  
  83. #define resumeLabelsOn(exception) resume_ ## exception:
  84. #define resumeLabelsOff(exception)
  85.  
  86. /*
  87.     When using SetExceptionOption do not put a ; or anything other than a comment
  88.     after the macro.
  89. */
  90.  
  91. /* We disable resume labels, and the SetExceptionOption macro because they are
  92.     not ANSI C happy */
  93. #define resumeLabel(exception) 
  94. #define SetExceptionOption(option)
  95.  
  96. /*
  97.     trace and notrace are used for the traceOption for dprintf. If trace is used then
  98.     the actual behavior cn be controled from Macsbug. The macros in Macsbug are traceGo
  99.     and traceBreak. traceGo is the default and execution will continue after the break.
  100.     If traceBreak is used then execution will halt.
  101. */
  102.  
  103. #define trace    "\p;dprintf;doTrace"
  104. #define    notrace    "\p;dprintf;mnop"
  105.  
  106. /*
  107.     traceon and debugon are used to test for options. For example:
  108.     
  109.     #if traceon
  110.     dprintf(trace, "Foo Happened %d", 10);
  111.     #endif
  112.     
  113.     #if debugon
  114.     dprintf(notrace, "Foo Happened %d", 10);
  115.     #endif
  116. */
  117.  
  118.  
  119. #define traceon ((DEBUGLEVEL > DEBUGWARN) && defined(TRACEON))
  120. #define debugon (DEBUGLEVEL > DEBUGWARN)
  121.  
  122. /*<FF>*/
  123. /**************************************************************************************
  124.  
  125. ROUTINE
  126.     dprintf
  127.  
  128. DESCRIPTION
  129.     dprintf is used like printf only the information is displayed in MacsBug.
  130.     traceOption is used to specify whether the execution should continue after the
  131.     break or not. Of the standard printf convertion characters only "n" is not
  132.     supported. In addition to the standard characters, the following are defined:
  133.     
  134.         b    Boolean. Outputs either true or false.
  135.         l    Point. Used like the d option. (the l is for location.)
  136.         L    point*. Used like the f option. (the L is for Location.)
  137.         F    Fixed point number. Used like the f option.
  138.         T    Fract number. Used like the f option.
  139.         r    Rect*. Displays the rect with each piece seperated by ", ". Used like the
  140.             d option.
  141.         R    rectangle*. Similar to r but for fixed point rectangles. Used like the
  142.             f option.
  143.         M    mapping. Displays the mapping seperated by ", " and "\n". The third column
  144.             is displayed as fract. Used like the f option.
  145.     
  146.     dprintf requires that the MacsBug dcmd dprintf is present.
  147.     
  148. EXAMPLE
  149.     The code:
  150.     
  151.         dprintf(notrace, "This is a Fract: %.8T", 0x70000000);
  152.     
  153.     Will display:
  154.     
  155.         This is a Fract: 1.75000000
  156.     
  157.     See the MPW C Reference for more information on printf.
  158.  
  159. **************************************************************************************/
  160.  
  161. void dprintf(StringPtr traceOption, char theFormat[], ...) = { 0xABFF, 0x594F };
  162.  
  163. /*<FF>*/
  164. /**************************************************************************************
  165.  
  166. ROUTINE check_dprintf
  167.  
  168. DESCRIPTION
  169.     if assertion is non-zero then assertion is returned. Otherwise the dprintf is
  170.     invoked and zero is returned.
  171.     
  172. Echo "                                                        ∂n∂
  173.     PROC                                                    ∂n∂
  174.     MOVE.L    (SP)+,D0        ; Pop value into D0                ∂n∂
  175.     BNE.S    @1                ; If !0 then branch                ∂n∂
  176.     DC.W    $ABFF            ; DebugStr                        ∂n∂
  177.     SUBQ    #4,SP            ; Fix stack for debugStr        ∂n∂
  178.     CLR.W    D0                ; result is zero                ∂n∂
  179. @1    SUBQ    #4,SP            ; Fix stack for pop                ∂n∂
  180.     ENDPROC                                                    ∂n∂
  181.     END                                                        ∂n∂
  182. " | Asm -l
  183.     
  184. **************************************************************************************/
  185.     
  186. void* check_dprintf(void* assertion, StringPtr traceOption, char theFormat[], ...) =
  187.     { 0x201F, 0x6606, 0xABFF, 0x594F, 0x4240, 0x594F };
  188.     
  189. /*<FF>*/
  190. /**************************************************************************************
  191.  
  192. ROUTINE checkpos_dprintf
  193.  
  194. DESCRIPTION
  195.     if assertion is non-zero then assertion is returned. Otherwise the dprintf is
  196.     invoked and zero is returned.
  197.     
  198. Echo "                                                        ∂n∂
  199.     PROC                                                    ∂n∂
  200.     MOVE.L    (SP)+,D0        ; Pop value into D0                ∂n∂
  201.     BGE.S    @1                ; If >= 0 then branch            ∂n∂
  202.     DC.W    $ABFF            ; DebugStr                        ∂n∂
  203.     SUBQ    #4,SP            ; Fix stack for debugStr        ∂n∂
  204.     CLR.W    D0                ; result is zero                ∂n∂
  205. @1    SUBQ    #4,SP            ; Fix stack for pop                ∂n∂
  206.     ENDPROC                                                    ∂n∂
  207.     END                                                        ∂n∂
  208. " | Asm -l
  209.     
  210. **************************************************************************************/
  211.     
  212. void* checkpos_dprintf(void* assertion, StringPtr traceOption, char theFormat[], ...) =
  213.     { 0x201F, 0x6C06, 0xABFF, 0x594F, 0x4240, 0x594F };
  214.  
  215. /*<FF>*/
  216. /**************************************************************************************
  217.  
  218. MACRO
  219.     check
  220.  
  221. DESCRIPTION
  222.     If DEBUGON or DEBUGFULL are defined then check will test the assertion and if it
  223.     failes break to the Debugger and print the assertion. If DEBUGON or DEBUGFULL are
  224.     not defined then check does nothing.
  225.  
  226. EXAMPLE
  227.     check is very useful for testing preconditions. In the below example DoStuff is
  228.     defined to take a handle to some object. It is a precondition of DoStuff that the
  229.     handle must not be nil (and therefore is the callers resposibility to ensure that
  230.     it is not.
  231.  
  232.         void DoStuff(Handle h)
  233.         {
  234.             check(h);
  235.             (FooType)(*h)->fooField = 0;
  236.         } 
  237.     
  238.     Durring testing, however, if DEBUGFULL where defined and a caller did not live up
  239.     to the contract by passing in a nil handle then a break would occure with the
  240.     following:
  241.     
  242.         Assertion "h" Failed
  243.         File: FooDisk:FooFile
  244.         Line: 3
  245.  
  246. **************************************************************************************/
  247.  
  248. #if DEBUGLEVEL==DEBUGON
  249.  
  250. #define check(assertion)                                                \
  251.     if (true) {                                                            \
  252.         if (assertion) ;                                                \
  253.         else {                                                            \
  254.             dprintf(notrace, "Assertion \"%s\" Failed",    #assertion);    \
  255.         }                                                                \
  256.     } else PlaceHolder()
  257.  
  258. #elif DEBUGLEVEL==DEBUGFULL
  259.  
  260. #define check(assertion)                                                \
  261.     if (true) {                                                            \
  262.         if (assertion) ;                                                \
  263.         else {                                                            \
  264.             dprintf(notrace,    "Assertion \"%s\" Failed\n"                \
  265.                                 "File: %s\n"                            \
  266.                                 "Line: %d",                                \
  267.                 #assertion, __FILE__, __LINE__);                        \
  268.         }                                                                \
  269.     } else PlaceHolder()
  270.  
  271. #else
  272.  
  273. #define check(assertion)
  274.  
  275. #endif
  276.  
  277. /*<FF>*/
  278. /**************************************************************************************
  279.  
  280. MACRO
  281.     ncheck
  282.  
  283. DESCRIPTION
  284.     ncheck is the same as check only it requires that the assertion is false.
  285.  
  286. EXAMPLE
  287.     ncheck is very useful for testing results when no recovery can be taken even if
  288.     the action fails. This is most commen durring clean up.
  289.  
  290.         void DisposeStuff(shape theShape)
  291.         {
  292.             DisposeShape(theShape);
  293.             ncheck(GetError());
  294.         } 
  295.     
  296.     If DEBUGFULL where defined and for some reason the dealocation failed then the
  297.     following would be reported:
  298.     
  299.         Assertion "!(GetError() [= -108])" Failed
  300.         File: FooDisk:FooFile
  301.         Line: 3
  302.  
  303. **************************************************************************************/
  304.  
  305. #if    DEBUGLEVEL==DEBUGON
  306.  
  307. #define ncheck(assertion)                                                \
  308.     if (true) {                                                            \
  309.         void*    __privateAssertion    = (void*)(assertion);                \
  310.                                                                         \
  311.         if (__privateAssertion) {                                        \
  312.             dprintf(notrace, "Assertion \"!(%s [= 0x%08X])\" Failed",    \
  313.                 #assertion, __privateAssertion);                        \
  314.         }                                                                \
  315.     } else PlaceHolder()
  316.  
  317. #elif DEBUGLEVEL==DEBUGFULL
  318.  
  319. #define ncheck(assertion)                                                    \
  320.     if (true) {                                                                \
  321.         void*    __privateAssertion    = (void*)(assertion);                    \
  322.                                                                             \
  323.         if (__privateAssertion) {                                            \
  324.             dprintf(notrace,    "Assertion \"!(%s [= 0x%08X])\" Failed\n"    \
  325.                                 "File: %s\n"                                \
  326.                                 "Line: %d",                                    \
  327.             #assertion, __privateAssertion, __FILE__, __LINE__);            \
  328.         }                                                                    \
  329.     } else PlaceHolder()
  330.  
  331. #else
  332.  
  333. #define ncheck(assertion)
  334.  
  335. #endif
  336.  
  337. /*<FF>*/
  338. /**************************************************************************************
  339.  
  340. MACRO
  341.     check_action
  342.  
  343. DESCRIPTION
  344.     If DEBUGON or DEBUGFULL are defined then check_action will test the assertion and
  345.     if it failes break to the Debugger and print the assertion then execute the
  346.     statement. If DEBUGON or DEBUGFULL are not defined then check_action does nothing.
  347.  
  348. **************************************************************************************/
  349.  
  350. #if DEBUGLEVEL==DEBUGON
  351.  
  352. #define check_action(assertion, action)                                    \
  353.     if (true) {                                                            \
  354.         if (assertion) ;                                                \
  355.         else {                                                            \
  356.             dprintf(notrace, "Assertion \"%s\" Failed",    #assertion);    \
  357.             { action }                                                    \
  358.         }                                                                \
  359.     } else PlaceHolder()
  360.  
  361. #elif DEBUGLEVEL==DEBUGFULL
  362.  
  363. #define check_action(assertion, action)                                    \
  364.     if (true) {                                                            \
  365.         if (assertion) ;                                                \
  366.         else {                                                            \
  367.             dprintf(notrace,    "Assertion \"%s\" Failed\n"                \
  368.                                 "File: %s\n"                            \
  369.                                 "Line: %d",                                \
  370.                 #assertion, __FILE__, __LINE__);                        \
  371.             { action }                                                    \
  372.         }                                                                \
  373.     } else PlaceHolder()
  374.  
  375. #else
  376.  
  377. #define check_action(assertion, action)
  378.  
  379. #endif
  380.  
  381. /*<FF>*/
  382. /**************************************************************************************
  383.  
  384. MACRO
  385.     ncheck_action
  386.  
  387. DESCRIPTION
  388.     If DEBUGON or DEBUGFULL are defined then check_action will evaluate the assertion
  389.     and if it evaluates to non-zero break to the Debugger and print the assertion then
  390.     execute the statement. If DEBUGON or DEBUGFULL are not defined then ncheck_action
  391.     does nothing.
  392.  
  393. **************************************************************************************/
  394.  
  395. #if    DEBUGLEVEL==DEBUGON
  396.  
  397. #define ncheck_action(assertion, action)                                            \
  398.     if (true) {                                                                        \
  399.         void*    __privateAssertion    = (void*)(assertion);                            \
  400.                                                                                     \
  401.         if (__privateAssertion) {                                                    \
  402.             dprintf(notrace, "Assertion \"!(%s [= 0x%08X])\" Failed",                \
  403.                 #assertion, __privateAssertion);                                    \
  404.             { action }                                                                \
  405.         }                                                                            \
  406.     } else PlaceHolder()
  407.  
  408. #elif DEBUGLEVEL==DEBUGFULL
  409.  
  410. #define ncheck_action(assertion, action)                                            \
  411.     if (true) {                                                                        \
  412.         void*    __privateAssertion    = (void*)(assertion);                            \
  413.                                                                                     \
  414.         if (__privateAssertion) {                                                    \
  415.             dprintf(notrace,    "Assertion \"!(%s [= 0x%08X])\" Failed\n"            \
  416.                                 "File: %s\n"                                        \
  417.                                 "Line: %d",                                            \
  418.             #assertion, __privateAssertion, __FILE__, __LINE__);                    \
  419.             { action }                                                                \
  420.         }                                                                            \
  421.     } else PlaceHolder()
  422.  
  423. #else
  424.  
  425. #define ncheck_action(assertion, action)
  426.  
  427. #endif
  428.  
  429. /*<FF>*/
  430. /**************************************************************************************
  431.  
  432. MACRO
  433.     require
  434.  
  435. DESCRIPTION
  436.     require tests the assertion just as check does (with a break into the Debugger if
  437.     the assertion failed and DEBUGON or DEBUGFULL was defined). If the assertion fails
  438.     then a goto exception is executed.
  439.  
  440. EXAMPLE
  441.     OSErr DoStuff(void)
  442.     {
  443.         FooTypeHandle        hFoo;
  444.         BananaTypeHandle    hBanana;
  445.         
  446.         hFoo = NewHandle(sizeof(FooType));
  447.         require(hFoo, NewHandle_hFoo);
  448.         
  449.         hBanana = NewHandle(&hBanana, sizeof(BananaType));
  450.         require(hBanana, NewHandle_hBanana);
  451.         
  452.         return(noErr);
  453.         
  454.     NewHandle_hBanana:
  455.         DisposHandle(hFoo);
  456.     NewHandle_hFoo:
  457.         return(memFullErr);
  458.     }
  459.  
  460. **************************************************************************************/
  461.  
  462. #if DEBUGLEVEL==DEBUGON
  463.  
  464. #define require(assertion, exception)                                    \
  465.     if (true) {                                                            \
  466.         if (assertion) ;                                                \
  467.         else {                                                            \
  468.             dprintf(notrace,    "Assertion \"%s\" Failed\n"                \
  469.                                 "Exception \"%s\" Raised",                \
  470.             #assertion, #exception);                                    \
  471.             goto exception;                                                \
  472.             resumeLabel(exception);                                        \
  473.         }                                                                \
  474.     } else PlaceHolder()
  475.  
  476. #elif DEBUGLEVEL==DEBUGFULL
  477.  
  478. #define require(assertion, exception)                                    \
  479.     if (true) {                                                            \
  480.         if (assertion) ;                                                \
  481.         else {                                                            \
  482.             dprintf(notrace,    "Assertion \"%s\" Failed\n"                \
  483.                                 "Exception \"%s\" Raised\n"                \
  484.                                 "File: %s\n"                            \
  485.                                 "Line: %d",                                \
  486.                 #assertion, #exception, __FILE__, __LINE__);            \
  487.             goto exception;                                                \
  488.             resumeLabel(exception);                                        \
  489.         }                                                                \
  490.     } else PlaceHolder()
  491.  
  492. #else
  493.  
  494. #define require(assertion, exception)                                    \
  495.     if (true) {                                                            \
  496.         if (assertion) ;                                                \
  497.         else {                                                            \
  498.             goto exception;                                                \
  499.             resumeLabel(exception);                                        \
  500.         }                                                                \
  501.     } else PlaceHolder()
  502.  
  503. #endif
  504.  
  505. /*<FF>*/
  506. /**************************************************************************************
  507.  
  508. MACRO
  509.     nrequire
  510.  
  511. DESCRIPTION
  512.     nrequire is the same as require except that it insures that assertion is false.
  513.  
  514. EXAMPLE
  515.     OSErr DoStuff(void)
  516.     {
  517.         OSErr                theError;
  518.         FooTypeHandle        hFoo;
  519.         BananaTypeHandle    hBanana;
  520.         
  521.         theError = MNewHandle(&hFoo, sizeof(FooType));
  522.         nrequire(theError, MNewHandle_hFoo);
  523.         
  524.         theError = MNewHandle(&hBanana, sizeof(BananaType));
  525.         nrequire(theError, MNewHandle_hBanana);
  526.         
  527.         return(noErr);
  528.         
  529.     MNewHandle_hBanana:
  530.         (void)MDisposHandle(&hFoo);
  531.     MNewHandle_hFoo:
  532.         return(theError);
  533.     }
  534.  
  535. **************************************************************************************/
  536.  
  537. #if DEBUGLEVEL==DEBUGON
  538.  
  539. #define nrequire(assertion, exception)                                                \
  540.     if (true) {                                                                        \
  541.         void*    __privateAssertion    = (void*)(assertion);                            \
  542.                                                                                     \
  543.         if (__privateAssertion) {                                                    \
  544.             dprintf(notrace,    "Assertion \"!(%s [= 0x%08X])\" Failed\n"            \
  545.                                 "Exception \"%s\" Raised",                            \
  546.                 #assertion, __privateAssertion, #exception);                        \
  547.             goto exception;                                                            \
  548.             resumeLabel(exception);                                                    \
  549.         }                                                                            \
  550.     } else PlaceHolder()
  551.  
  552. #elif DEBUGLEVEL==DEBUGFULL
  553.  
  554. #define nrequire(assertion, exception)                                                \
  555.     if (true) {                                                                        \
  556.         void*    __privateAssertion    = (void*)(assertion);                            \
  557.                                                                                     \
  558.         if (__privateAssertion) {                                                    \
  559.             dprintf(notrace,    "Assertion \"!(%s [= 0x%08X])\" Failed\n"            \
  560.                                 "Exception \"%s\" Raised\n"                            \
  561.                                 "File: %s\n"                                        \
  562.                                 "Line: %d",                                            \
  563.                 #assertion, __privateAssertion, #exception, __FILE__,                \
  564.                 __LINE__);                                                            \
  565.             goto exception;                                                            \
  566.             resumeLabel(exception);                                                    \
  567.         }                                                                            \
  568.     } else PlaceHolder()
  569.  
  570. #else
  571.  
  572. #define nrequire(assertion, exception)                                                \
  573.     if (true) {                                                                        \
  574.         if (assertion) {                                                            \
  575.             goto exception;                                                            \
  576.             resumeLabel(exception);                                                    \
  577.         }                                                                            \
  578.     } else PlaceHolder()
  579.  
  580. #endif
  581.  
  582. /*<FF>*/
  583. /**************************************************************************************
  584.  
  585. MACRO
  586.     require_action
  587.  
  588. DESCRIPTION
  589.     require_action is identical to require except if the assertion fails then action
  590.     is executed.
  591.  
  592. EXAMPLE
  593.     OSErr DoStuff(void)
  594.     {
  595.         FooTypeHandle        hFoo;
  596.         BananaTypeHandle    hBanana;
  597.         OSErr                theError;
  598.         
  599.         hFoo = NewHandle(sizeof(FooType));
  600.         require_action(hFoo, NewHandle_hFoo, theError = MemError(););
  601.         
  602.         hBanana = NewHandle(&hBanana, sizeof(BananaType));
  603.         require_action(hBanana, NewHandle_hBanana, theError = MemError(););
  604.         
  605.         return(noErr);
  606.         
  607.     NewHandle_hBanana:
  608.         DisposHandle(hFoo);
  609.     NewHandle_hFoo:
  610.         return(theError);
  611.     }
  612.  
  613. **************************************************************************************/
  614.  
  615. #if DEBUGLEVEL==DEBUGON
  616.  
  617. #define require_action(assertion, exception, action)                    \
  618.     if (true) {                                                            \
  619.         if (assertion) ;                                                \
  620.         else {                                                            \
  621.             dprintf(notrace,    "Assertion \"%s\" Failed\n"                \
  622.                                 "Exception \"%s\" Raised",                \
  623.             #assertion, #exception);                                    \
  624.             { action }                                                    \
  625.             goto exception;                                                \
  626.             resumeLabel(exception);                                        \
  627.         }                                                                \
  628.     } else PlaceHolder()
  629.  
  630. #elif DEBUGLEVEL==DEBUGFULL
  631.  
  632. #define require_action(assertion, exception, action)                    \
  633.     if (true) {                                                            \
  634.         if (assertion) ;                                                \
  635.         else {                                                            \
  636.             dprintf(notrace,    "Assertion \"%s\" Failed\n"                \
  637.                                 "Exception \"%s\" Raised\n"                \
  638.                                 "File: %s\n"                            \
  639.                                 "Line: %d",                                \
  640.                 #assertion, #exception, __FILE__, __LINE__);            \
  641.             { action }                                                    \
  642.             goto exception;                                                \
  643.             resumeLabel(exception);                                        \
  644.         }                                                                \
  645.     } else PlaceHolder()
  646.  
  647. #else
  648.  
  649. #define require_action(assertion, exception, action)                    \
  650.     if (true) {                                                            \
  651.         if (assertion) ;                                                \
  652.         else {                                                            \
  653.             { action }                                                    \
  654.             goto exception;                                                \
  655.             resumeLabel(exception);                                        \
  656.         }                                                                \
  657.     } else PlaceHolder()
  658.  
  659. #endif
  660.  
  661. /*<FF>*/
  662. /**************************************************************************************
  663.  
  664. MACRO
  665.     nrequire_action
  666.  
  667. DESCRIPTION
  668.     nrequire_action is the same as nrequire except it executes action when the
  669.     assertion is true.
  670.  
  671. EXAMPLE
  672.     void *DoStuff(void)
  673.     {
  674.         OSErr                theError;
  675.         FooTypeHandle        hFoo;
  676.         BananaTypeHandle    hBanana;
  677.         void *                result;
  678.         
  679.         theError = GetSpecialHandle(&hFoo);
  680.         nrequire_action(theError, GetSpecialHandle, result = nil);
  681.         
  682.         result = (*hFoo)->theStuff;
  683.         
  684.         // Just let if fall through in this contrived example
  685.         
  686. GetSpecialHandle:
  687.         return(result);
  688.     }
  689.  
  690. **************************************************************************************/
  691.  
  692. #if DEBUGLEVEL==DEBUGON
  693.  
  694. #define nrequire_action(assertion, exception, action)                                \
  695.     if (true) {                                                                        \
  696.         void*    __privateAssertion    = (void*)(assertion);                            \
  697.                                                                                     \
  698.         if (__privateAssertion) {                                                    \
  699.             dprintf(notrace,    "Assertion \"!(%s [= 0x%08X])\" Failed\n"            \
  700.                                 "Exception \"%s\" Raised",                            \
  701.                 #assertion, __privateAssertion, #exception);                        \
  702.             { action }                                                                \
  703.             goto exception;                                                            \
  704.             resumeLabel(exception);                                                    \
  705.         }                                                                            \
  706.     } else PlaceHolder()
  707.  
  708. #elif DEBUGLEVEL==DEBUGFULL
  709.  
  710. #define nrequire_action(assertion, exception, action)                                \
  711.     if (true) {                                                                        \
  712.         void*    __privateAssertion    = (void*)(assertion);                            \
  713.                                                                                     \
  714.         if (__privateAssertion) {                                                    \
  715.             dprintf(notrace,    "Assertion \"!(%s [= 0x%08X])\" Failed\n"            \
  716.                                 "Exception \"%s\" Raised\n"                            \
  717.                                 "File: %s\n"                                        \
  718.                                 "Line: %d",                                            \
  719.                 #assertion, __privateAssertion, #exception, __FILE__,                \
  720.                 __LINE__);                                                            \
  721.             { action }                                                                \
  722.             goto exception;                                                            \
  723.             resumeLabel(exception);                                                    \
  724.         }                                                                            \
  725.     } else PlaceHolder()
  726.  
  727. #else
  728.  
  729. #define nrequire_action(assertion, exception, action)                    \
  730.     if (true) {                                                            \
  731.         if (assertion) {                                                \
  732.             { action }                                                    \
  733.             goto exception;                                                \
  734.             resumeLabel(exception);                                        \
  735.         }                                                                \
  736.     } else PlaceHolder()
  737.  
  738. #endif
  739.  
  740. /*<FF>*/
  741. /**************************************************************************************
  742.  
  743. MACRO
  744.     retry
  745.  
  746. DESCRIPTION
  747.     retry is used to start a routine over if the routine fails. Variable initialization
  748.     is not redone so variables can be changed to retry the routine under different
  749.     circumstances. Routine parameters should not be changed or the routine will no
  750.     longer be fulfilling its contract.
  751.  
  752. EXAMPLE
  753.     OSErr DoStuff(void)
  754.     {
  755.         OSErr                theError;
  756.         Handle                h;
  757.         Int16                iSize;
  758.         Int16                iPieces = kGoodNumber;
  759.         Int16                i;
  760.         
  761.     start:
  762.     
  763.         iSize = kFullSize / iPieces;
  764.         
  765.         for (i = 0; i <= iPieces; i++) {
  766.             theError = MNewHandle(&h, iSize);
  767.             nrequire(theError, MNewHandle);
  768.             .
  769.             .
  770.             .
  771.             theError = MDisposeHandle(&h);
  772.             ncheck(theError);
  773.         }
  774.         
  775.         return(noErr);
  776.                 
  777.     MNewHandle:
  778.  
  779.         (void)MDisposeHandle(&h);
  780.         iPieces += kMore;
  781.         
  782.         if (iPieces < kMaxPieces)
  783.             retry;
  784.         else
  785.             return(theError);
  786.     }
  787.  
  788. **************************************************************************************/
  789.  
  790. #define retry                                 \
  791.     if (true) {                                \
  792.         goto start;                            \
  793.     } else PlaceHolder()
  794.     
  795.     
  796. /*<FF>*/
  797. /**************************************************************************************
  798.  
  799. MACRO
  800.     resume
  801.  
  802. DESCRIPTION
  803.     resume is used to resume execution at the point where an exception occured. Below
  804.     is a very contrived example of it's use. Note that this example also shows how
  805.     to handle an exception in an exception. Although this is rarly neccisary sometimes
  806.     it can be useful but make sure that it is clearly commented.
  807.  
  808. EXAMPLE
  809.     Boolean DoStuff(Boolean ***theSettings)
  810.     {
  811.         *theSettings = (Boolean **)GetResource('STIN', 128);
  812.         require(*theSettings, GetResource);
  813.         
  814.         // Execution will resume here
  815.         
  816.         return(***theSettings);
  817.     
  818.     GetResource:
  819.         *theSettings = (Boolean **)NewHandle(sizeof(Boolean));
  820.         require(*theSettings, NewHandle);
  821.         *theSettings = false;
  822.         resume(GetResource);
  823.         
  824.     // Secondary exceptions
  825.         
  826.     NewHandle:
  827.         return(false);
  828.     }
  829.  
  830. **************************************************************************************/
  831.  
  832.  
  833. #define resume(exception)                    \
  834.     if (true) {                                \
  835.         goto resume_ ## exception;            \
  836.     } else PlaceHolder()
  837.  
  838.  
  839. /*<FF>*/
  840. /*************************************************************************************/
  841.  
  842. #endif